﻿using System.Collections.Generic;
using System.Text.Json.Serialization;
using LightCAD.MathLib;
namespace LightCAD.Core.Elements
{
    /// <summary>
    /// 对齐标注
    /// </summary>
    public class DimAligned : LcElement
    {
        //标注两边的线第一根线的起点
        [JsonInclude, JsonPropertyName("F")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 First;
        //标注两边的线第二根线的起点
        [JsonInclude, JsonPropertyName("S")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 Second;
        //标注两边的线的结束点
        [JsonInclude, JsonPropertyName("T")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 Third;
        //标注底线的线的中心点
        [JsonInclude, JsonPropertyName("Fifth")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 Fifth;
        public Vector2 Vector;

        public DimAligned()
        {
            this.Type = BuiltinElementType.DimAligned;
        }
        public DimAligned(Vector2 first, Vector2 second, Vector2 third) : this()
        {
            this.First = first;
            this.Second = second;
            this.Third = third;
            this.Fifth = new Vector2((GetVector2D(this.First).X + GetVector2D(this.Second).X) / 2, (GetVector2D(this.First).Y + GetVector2D(this.Second).Y) / 2);
        }
        public DimAligned(double startX, double startY, double endX, double endY) : this()
        {
            this.First.X = startX;
            this.First.Y = startY;
            this.Second.X = endX;
            this.Second.Y = endY;
        }
        public LcText Text { get; set; }

        public double Length
        {
            get
            {
                return (this.Second - this.First).Length();
            }
        }

        [JsonIgnore]
        public double Angle
        {
            get
            {
                return (this.Second - this.First).Angle();
            }
        }

        [JsonIgnore]
        public double DeltaX
        {
            get
            {
                return this.Second.X - this.First.X;
            }
        }

        [JsonIgnore]
        public double DeltaY
        {
            get
            {
                return this.Second.Y - this.First.Y;
            }
        }
        public Vector2 GetVector2D(Vector2 point)
        {
            var pt = Line2d.GetFootofperpendicular(this.Third, this.First, this.Second);
            //向量
            var vector = new Vector2(this.Third.X - pt.X, this.Third.Y - pt.Y);
            return new Vector2(point.X + vector.X, point.Y + vector.Y);
        }

        public override LcElement Clone()
        {
            var clone = new DimAligned();
            clone.Copy(this);
            return clone;
        }

        public override void Copy(LcElement src)
        {
            var dim = ((DimAligned)src);
        }
        public void Set(Vector2 first = null, Vector2 second = null, Vector2 third = null, bool fireChangedEvent = true)
        {
            //PropertySetter:Start,End
            if (!fireChangedEvent)
            {
                if (first != null) this.First = first;
                if (second != null) this.Second = second;
                if (third != null) this.Third = third;
            }
            else
            {
                bool chg_start = (first != null && first != this.First);
                if (chg_start)
                {
                    OnPropertyChangedBefore(nameof(First), this.First, first);
                    var oldValue = this.First;
                    this.First = first;
                    OnPropertyChangedAfter(nameof(First), oldValue, this.First);
                }
                bool chg_end = (second != null && second != this.Second);
                if (chg_end)
                {
                    OnPropertyChangedBefore(nameof(Second), this.Second, second);
                    var oldValue = this.Second;
                    this.Second = second;
                    OnPropertyChangedAfter(nameof(Second), oldValue, this.Second);
                }
                bool chg_third = (third != null && third != this.Third);
                if (chg_third)
                {
                    OnPropertyChangedBefore(nameof(Second), this.Second, second);
                    var oldValue = this.Second;
                    this.Third = third;
                    this.Fifth = third;
                    OnPropertyChangedAfter(nameof(Second), oldValue, this.Second);
                }
            }
        }
        public override Box2 GetBoundingBox()
        {
            return new Box2().SetFromPoints(this.First, this.Second);
        }
        public override Box2 GetBoundingBox(Matrix3 matrix)
        {
            return new Box2().SetFromPoints(matrix.MultiplyPoint(this.First), matrix.MultiplyPoint(this.Second));
        }
        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            var thisBox = this.BoundingBox;
            //if (!thisBox.IntersectWith(testPoly.BoundingBox))
            //{
            //    //如果元素盒子，与多边形盒子不相交，那就可能不相交
            //    return false;
            //}
            var pt = Line2d.GetFootofperpendicular(this.Third, this.First, this.Second);
            //向量
            var vector = new Vector2(this.Third.X - pt.X, this.Third.Y - pt.Y);
            Vector2 FristEnd = GetVector2D(this.First);
            Vector2 SecondEnd = GetVector2D(this.Second);

            return GeoUtils.IsPolygonIntersectLine(testPoly.Points, this.First, FristEnd)
           || GeoUtils.IsPolygonContainsLine(testPoly.Points, this.First, FristEnd)
           || GeoUtils.IsPolygonIntersectLine(testPoly.Points, this.Second, SecondEnd)
           || GeoUtils.IsPolygonContainsLine(testPoly.Points, this.Second, SecondEnd)
           || GeoUtils.IsPolygonIntersectLine(testPoly.Points, FristEnd, SecondEnd)
           || GeoUtils.IsPolygonContainsLine(testPoly.Points, FristEnd, SecondEnd);

        }

        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                return false;
            }
            return GeoUtils.IsPolygonContainsLine(testPoly.Points, this.First, this.Second);
        }
        public override void Move(Vector2 startPoint, Vector2 endPoint)
        {
            Matrix3 matrix3 = Matrix3.GetMove(startPoint, endPoint);
            this.Set(matrix3.MultiplyPoint(this.First), matrix3.MultiplyPoint(this.Second));
            ResetBoundingBox();
        }

    }
}
